#include "HeartBeatChannelMaps.h"

#include <iomanip>
#include <ctime>
#include <chrono>
#include <iostream> // for log
#include "ServerImp.h"

namespace frame {
namespace imp {

HeartBeatChannelMaps::ChannelNode::ChannelNode(ServerChannelImp * channel
    , uint64_t maxHeartBeatReadTimespan, uint64_t maxHeartBeatWriteTimespan)
: channel(channel)
, maxHeartBeatReadTimespan(maxHeartBeatReadTimespan)
, maxHeartBeatWriteTimespan(maxHeartBeatWriteTimespan)
{
    lastReadTimestamp = now(); 
    lastWriteTimestamp = now();
    //std::cout << "init: lastReadTimestamp"  << lastReadTimestamp << std::endl;
    //std::cout << "init: lastWriteTimestamp"  << lastWriteTimestamp << std::endl;
}
void HeartBeatChannelMaps::ChannelNode::checkReadTimestamp(){
    if(now() >= lastReadTimestamp + std::chrono::milliseconds(maxHeartBeatReadTimespan)){
        std::cout << "check read timeout, to disconnect" << std::endl;
        if(channel != nullptr){
            channel->disconnect();
            channel = nullptr;
        }
        else{
            std::cout << "channel is nullptr" << std::endl;
        }
        updateLastReadTimestamp();
    }
}
void HeartBeatChannelMaps::ChannelNode::checkWriteTimestamp(){
    if(now() >= lastWriteTimestamp + std::chrono::milliseconds(maxHeartBeatWriteTimespan)){
        //TODO: HeartBeatDatagramWriter(channel);
        std::cout << "check write timeout, write:Hello" << std::endl;
        if(channel != nullptr){
            channel->write("hello", 5);
        }
        else {
            std::cout << "async timeout for check Write, but channel is nullptr" << std::endl;
        }
        updateLastWriteTimestamp();
    }
}

std::chrono::steady_clock::time_point HeartBeatChannelMaps::ChannelNode::now(){
    return std::chrono::steady_clock::now();
}

bool HeartBeatChannelMaps::addChannel(uint64_t channelId, uint64_t maxHeartBeatReadTimespan, uint64_t maxHeartBeatWriteTimespan, ServerChannelImp * channelImp){
    if(maps.find(channelId) == maps.end()){
        maps.insert(std::make_pair(channelId, new ChannelNode(channelImp, maxHeartBeatReadTimespan, maxHeartBeatWriteTimespan)));
        return true;
    }
    return false;
}
bool HeartBeatChannelMaps::removeChannel(uint64_t channelId){
    auto iter = maps.find(channelId);
    if(iter != maps.end()){
        delete iter->second;
        maps.erase(iter);
        return true;
    }
    return false;
}
HeartBeatChannelMaps::ChannelNode * HeartBeatChannelMaps::getChannel(uint64_t channelId){
    auto iter = maps.find(channelId);
    return (iter != maps.end()) ? iter->second : nullptr;
}

} //end of namespace  imp
} //end of namespace  frame
